package com.mcb.autopublish.demos.web.service;

import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.mcb.autopublish.demos.web.constant.NumberConstant;
import com.mcb.autopublish.demos.web.po.Books;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.IOException;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mcb.autopublish.demos.web.dto.request.ArticleQuestionSonMcQueryRequest;
import com.mcb.autopublish.demos.web.dto.response.ArticleQuestionSonMcResponse;
import com.mcb.autopublish.demos.web.vo.AiNews;
import com.mcb.autopublish.demos.web.vo.WeChatArticle;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

import javax.annotation.Resource;

import static com.mcb.autopublish.demos.web.constant.AutoPublishConstant.*;
import static com.mcb.autopublish.demos.web.util.CommonUtils.*;
import static com.mcb.autopublish.demos.web.util.CommonUtils.getDataByTongYiQianWen;

import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;

/**
 * <p>
 *
 * </p>
 *
 * @author mcb
 * @since 2024/5/28
 */
@Service
@Slf4j
public class AutoHandleServiceImpl implements AutoHandleService {


    @Autowired
    private CacheManager cacheManager;

    @Resource
    private ArticleQuestionSonMcService articleQuestionSonMcService;

    @Resource
    private ArticleQuestionMcService articleQuestionMcService;

    @Value("${my.custom.property}")
    private String myCustomProperty;

    @Autowired
    private BooksService booksService;

    /**
     * 题目
     */
    public static final String QUESTION = "详细讲解一下JVM中的内存管理优化";

    /**
     * 题目
     */
    public static final String QUESTION_ANSWER = "问题：\n" + QUESTION + "\n" +
            "要求：\n" +
            "1.根据问题给出答案，语言严谨，高级专家级别，并给出实际的案例。\n" +
            "2.格式: MarkDown格式，符合年轻人的审美。\n" +
            "备注：请直接生成，不要出现非答案的文字。";


    /**
     * 1. 提取Excel中的系列图书的名字。
     * 2. 给出该系列图书中包含的所有书籍的名字。
     * 3. 对每本书出30道填空题 10道简答题，并给出答案。（英文版）
     * 4. 对英文版的题目以及答案翻译成中文。
     * 5. 输出。
     *
     * @param
     * @throws Exception
     */
    public void autoExtractAndGenerateArticleOld(String series, String filePath) throws Exception {
        log.info("1. 提取Excel中的系列图书的名字");
        // 1.1 路径
        // 1.2 提取Excel文件中的第一列中所有行的数据
        List<String> titleList = new ArrayList<>();
        log.info("1.3 提取到的数据：{}", titleList.toString());
        for (String title : titleList) {
            log.info("2. 给出该系列图书中包含的所有书籍的名字。");
            // 2.1 组装问题。
            String questionToTYQW = "问题：图书：" + title + "，请给出该图书具体有几本书，给出全部的具体书的名字。\n" +
                    "注意，在你回答答案的时候，直接回复结果，不要有多余的字。";
            // 2.2 对接接口，获取答案。
            GenerationResult jokeResult = getDataByTongYiQianWen(questionToTYQW);
            String joke = jokeResult.getOutput().getChoices().get(0).getMessage().getContent();
            // 2.3 保存到数据库中。
            log.info("2.4 保存到数据库中。");
            log.info("保存的数据是：{}", joke);
            // 通过回车分割字符串
            String[] split = joke.split("\n");
            // 将数组转换成 List<String>
            List<String> list = Arrays.asList(split);
            // 转换成 List<Books>
            List<Books> booksList = new ArrayList<>();
            for (String s : list) {
                Books books = new Books();
                books.setName(s);
                books.setSeries(series);
                String questionToTYQW2 = "图书：" + s + "，请问具体有多少页？注意，在你回答答案的时候，直接回复int类型的结果，不要有多余的字。";
                GenerationResult jokeResult2 = getDataByTongYiQianWen(questionToTYQW2);
                books.setPage(Integer.parseInt(jokeResult2.getOutput().getChoices().get(0).getMessage().getContent()));
                String questionToTYQW3 = "根据图书：" + s + "，给出英文版的 30道填空题 10道简答题，并给出答案。注意，在你回答答案的时候，请直接回复结果，不要有多余的字。";
                GenerationResult jokeResult3 = getDataByTongYiQianWen(questionToTYQW3);
                String content3 = jokeResult3.getOutput().getChoices().get(0).getMessage().getContent();
                books.setQuestion(content3);
                String questionToTYQW4 = "根据该文本：" + content3 + "，直接翻译成中文。注意，在你回答答案的时候，请直接回复结果，不要有多余的字。";
                GenerationResult jokeResult4 = getDataByTongYiQianWen(questionToTYQW4);
                books.setQuestionEn(jokeResult4.getOutput().getChoices().get(0).getMessage().getContent());
                booksList.add(books);
            }
            Collection<Books> entityList = new ArrayList<>(booksList);
            // 批量保存到数据库中。
            booksService.saveBatch(entityList);
        }

    }


    /**
     * 获取Excel的数据
     *
     * @return
     */
    public Map<String, String> getTitle(String filePath, int sheetAt) {

        Map<String, String> map = new LinkedHashMap<>();
        try (
                FileInputStream fis = new FileInputStream(filePath);
                Workbook workbook = new XSSFWorkbook(fis)) {

            // 假设我们要读取第一个工作表
            Sheet sheet = workbook.getSheetAt(sheetAt);
            int i = 1;

            // 遍历所有行（从第一行开始）
            for (Row row : sheet) {
                // 获取第一列的单元格，注意这里的索引是0表示第一列
                Cell cell0 = row.getCell(0);
                Cell cell1 = row.getCell(1);

                // 如果该行的第一列有内容，则打印出来
                if (cell1 != null && cell0 != null) {
                    i++;
                    map.put(cell0.getStringCellValue(), cell1.getStringCellValue());
                }
            }

        } catch (
                IOException e) {
            e.printStackTrace();
        }
        return map;
    }


    /**
     * 基础版： 生成MarkDown格式文章
     *
     * @param
     * @throws Exception
     */
    @Override
    public void autoMarkDownArticle() throws Exception {
        log.info("生成MarkDown格式文章-开始");
        //  生成文章。
        GenerationResult dataByTongYiQianWen = getDataByTongYiQianWen(QUESTION_ANSWER);
        String markdownContent = dataByTongYiQianWen.getOutput().getChoices().get(0).getMessage().getContent();
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("D:\\Users\\Desktop\\马呈邦\\代码生成文章\\file.md"))) {
            writer.write(markdownContent);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * (1)自动保存公众号草稿(JAVA)
     *
     * @throws IOException
     */
    @Override
    public void autoPublishWeChatArticleJava() throws Exception {
        log.info("(1)自动保存公众号草稿(JAVA)-开始");
        log.info("myCustomProperty:{}", myCustomProperty);
        // 1. 获取问题和答案
        // 1.1 获取问题
        ArticleQuestionSonMcQueryRequest sonMcQueryRequest = new ArticleQuestionSonMcQueryRequest();
        sonMcQueryRequest.setAccessDate(new Date());
        List<ArticleQuestionSonMcResponse> articleQuestionSonMcList = articleQuestionSonMcService.getArticleQuestionSonMcList(sonMcQueryRequest);

        articleQuestionSonMcList.forEach(articleQuestionSonMcResponse -> {
            String question = articleQuestionSonMcResponse.getName();
            String questionToTYQW = "问题：\n" + question + "\n" +
                    "要求：\n" +
                    "1.根据问题给出答案，语言严谨，高级专家级别，并给出实际的案例。\n" +
                    "2.格式: MarkDown格式，符合年轻人的审美。\n" +
                    "备注：请直接生成，不要出现非答案的文字。";
            // 2. 自动保存公众号草稿-微信
            // 2.1 获取accessToken
            String accessToken = null;
            try {
                accessToken = getAccessToken();
                // 2.2 组装公众号文章
                String resultJson = assembleArticleForWeChatJava(question, questionToTYQW);
                // 2.3 请求微信接口-保存草稿
                getUrlConstants(WECHAT_URL_DRAFT_URL + accessToken, METHOD_POST, resultJson);
                log.info("(1)自动保存公众号草稿(JAVA)-结束");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        });

    }

    /**
     * 组装公众号文章-JAVA
     *
     * @return
     */
    public String assembleArticleForWeChatJava(String question, String questionToTYQW) throws Exception {

        // 2.1 生成文章。
        GenerationResult dataByTongYiQianWen = getDataByTongYiQianWen(questionToTYQW);
        String content = dataByTongYiQianWen.getOutput().getChoices().get(0).getMessage().getContent();
        // 将Markdown转换为HTML
        Parser parser = Parser.builder().build();
        HtmlRenderer renderer = HtmlRenderer.builder().build();
        // 将Markdown解析为AST（抽象语法树）
        Node document = parser.parse(content);

        // 将AST渲染为HTML
        String htmlOutput = renderer.render(document);
        GenerationResult jokeResult = getDataByTongYiQianWen("讲个段子，超级搞笑");
        WeChatArticle weChatArticle = getWeChatArticle(question, jokeResult, htmlOutput);
        return buildWeChatBaseInfo(weChatArticle);
    }

    private static @NotNull WeChatArticle getWeChatArticle(String title, GenerationResult jokeResult, String htmlOutput) {
        String joke = jokeResult.getOutput().getChoices().get(0).getMessage().getContent();
        WeChatArticle weChatArticle = new WeChatArticle();
        weChatArticle.setTitle(title);
        weChatArticle.setAuthor("小竹笋");
        weChatArticle.setDigest(joke);
        weChatArticle.setContent(htmlOutput);
        weChatArticle.setContent_source_url("");
        weChatArticle.setThumb_media_id("Fn0oiPBkKd-x3f2aTdU1XFaqm8IHZsGplqW7lAPdfTQ_5g1zwnBmOoSQ140NEF4J");
        weChatArticle.setNeed_open_comment("0");
        weChatArticle.setOnly_fans_can_comment("0");
        weChatArticle.setPic_crop_235_1("");
        weChatArticle.setPic_crop_1_1("");
        return weChatArticle;
    }

    /**
     * (2)自动保存公众号草稿(AI技术)
     *
     * @param
     * @throws Exception
     */
    @Override
    public void autoPublishWeChatArticleAI() throws Exception {
        log.info("代办");
    }

    /**
     * (3)自动保存公众号草稿(AI热点)
     */
    @Override
    public void autoPublishWeChatArticleAIHot() throws Exception {
        log.info("(3)自动保存公众号草稿(AI热点)-开始");
        // 1. 获取热点话题
        String hotTopics = getUrlConstants(AI_URL, METHOD_POST, URL_CONSTANTS);
        // 1.1 解析热点话题
        List<AiNews> aiNews = parseJson(hotTopics);

        // 2. 自动保存公众号草稿-微信
        // 2.1 获取accessToken
        String accessToken = getAccessToken();
        // 2.2 组装公众号文章
        String resultJson = assembleArticleForWeChatAIHot(aiNews);
        // 2.3 请求微信接口-保存草稿
        getUrlConstants(WECHAT_URL_DRAFT_URL + accessToken, METHOD_POST, resultJson);
        log.info("(3)自动保存公众号草稿(AI热点)-结束");
    }

    /**
     * 获取微信accessToken
     *
     * @return
     * @throws Exception
     */
    public String getAccessToken() throws Exception {
        // 动态获取accessToken
        String accessToken = cacheManager.getCache(WE_CHAT_MY_CACHE).get(WE_CHAT_ACCESS_TOKEN, String.class);
        if (Objects.isNull(accessToken)) {
            String accessTokenReturn = getUrlConstants(WECHAT_URL_ACCESS_TOKEN, METHOD_GET, "");
            accessToken = getJsonNode(accessTokenReturn, "access_token");
            Objects.requireNonNull(cacheManager.getCache(WE_CHAT_MY_CACHE)).put(WE_CHAT_ACCESS_TOKEN, accessToken);
        }
        log.info("accessToken的值是：{}", accessToken);
        return accessToken;
    }

    /**
     * 组装微信公众号文章内容-AI热点
     */
    public static String assembleArticleForWeChatAIHot(List<AiNews> aiNews) throws Exception {
        log.info("开始组装微信公众号文章内容");

        if (aiNews.isEmpty()) {
            log.info("热点话题为空,当前时间是：{}", new Date());
            return null;
        }
        // 1. 获取第一个热点话题
        AiNews aiNews1 = aiNews.get(0);
        String description = aiNews1.getDescription();

        // 2. 调用GPT生成摘要。
        GenerationResult result = getDataByTongYiQianWen(description + "，请生成一个摘要。");
        String digest = result.getOutput().getChoices().get(0).getMessage().getContent();

        // 3. 组装微信公众号文章
        WeChatArticle weChatArticle = new WeChatArticle();

        return buildWeChatBaseInfo(weChatArticle);
    }

    /**
     * 构建微信基础信息(公共)
     */
    public static String buildWeChatBaseInfo(WeChatArticle weChatArticle) {

        String resultJson = "";
        // 创建 ObjectMapper 对象
        ObjectMapper objectMapper = new ObjectMapper();

        // 构建文章列表
        List<Map<String, Object>> articles = new ArrayList<>();

        // 构建文章内容
        Map<String, Object> article = new HashMap<>();
        article.put("title", weChatArticle.getTitle());
        article.put("author", weChatArticle.getAuthor());
        article.put("digest", weChatArticle.getDigest());
        article.put("content", weChatArticle.getContent());
        article.put("content_source_url", weChatArticle.getContent_source_url());
        article.put("thumb_media_id", weChatArticle.getThumb_media_id());   // Fn0oiPBkKd-x3f2aTdU1XFaqm8IHZsGplqW7lAPdfTQ_5g1zwnBmOoSQ140NEF4J
        article.put("need_open_comment", weChatArticle.getNeed_open_comment());
        article.put("only_fans_can_comment", weChatArticle.getOnly_fans_can_comment());
        article.put("pic_crop_235_1", weChatArticle.getPic_crop_1_1());
        article.put("pic_crop_1_1", weChatArticle.getPic_crop_1_1());

        // 将文章添加到文章列表中
        articles.add(article);

        // 构建最终的 JSON 数据
        Map<String, Object> jsonData = new HashMap<>();
        jsonData.put("articles", articles);
        try {
            // 将 JSON 数据转换为字符串输出
            resultJson = objectMapper.writeValueAsString(jsonData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("微信公众号组装的内容是：{}", resultJson);
        return resultJson;
    }


    /**
     * 1. 提取Excel中的系列图书的名字。
     * 2. 给出该系列图书中包含的所有书籍的名字。
     * 3. 对每本书出30道填空题 10道简答题，并给出答案。（英文版）
     * 4. 对英文版的题目以及答案翻译成中文。
     * 5. 输出。
     *
     * @param
     * @throws Exception
     */
    @Override
    public void autoExtractAndGenerate(String filePath, int sheetAt) throws Exception {
        log.info("1. 提取Excel中的图书的名字");
        Map<String, String> title = getTitle(filePath, sheetAt);
        log.info("1.1 提取到的数据：{}", title.toString());
        int i = 1;
        // 遍历title
        for (Map.Entry<String, String> entry : title.entrySet()) {
            String name = entry.getKey();  // 书籍
            String series = entry.getValue();  // 系列
            log.info("2. 提问问题。");
            log.info("2.1 第{}本书；该问题的书籍是：{}; 所属系列{}", i, name, series);
            // 2.1 组装问题。
//            String questionToTYQW = "根据" + series + "的第一季中的图书：《" + name + "》，进行出题" +
//                    "要求：\n" +
//                    "1. 一共出30道题。其中：选择题10道、选词填空10道、简答题5道。而判断题、排序题：这两种任选一种，共出5道题就可以。备注：如果是判断题，请预留括号来打对错。简答题需要留白给孩子写。\n" +
//                    "2. 题目出完之后，在试卷的最后，给出每道题的答案，如果存在简单题，简答题也要有答案。\n" +
//                    "3. 题目的难度适合6-12岁儿童。\n" +
//                    "4. 语言：英语。\n" +
//                    "5. 请直接回答，不要有多余文字。" ;

            String questionToTYQW = "请给"+series+"的这本书"+name+"出30道英文阅读题，要求用到不同题型，格式可用于直接打印。直接回答，不要有多余文字" ;


            // 2.2 对接接口，获取答案。
            GenerationResult jokeResult = getDataByTongYiQianWen(questionToTYQW);
            String joke = jokeResult.getOutput().getChoices().get(0).getMessage().getContent();
            Books books = new Books();
            books.setName(name);
            books.setSeries(series);
            books.setQuestion(joke);
            String questionToTYQW4 = "根据该文本：" + joke + "，全部翻译成中文。";
            log.info("3.1 AI思考中。");
            GenerationResult jokeResult4 = getDataByTongYiQianWen(questionToTYQW4);
            String content = jokeResult4.getOutput().getChoices().get(0).getMessage().getContent();
            log.info("3.2 AI回复数据。答案为：{}", content);
            books.setQuestionEn(content);
            log.info("4.1 保存到数据库。");
            booksService.saveBooks(books);
            log.info("4.2 保存完成。");
            i++;
        }

    }

    /**
     * 保存到word
     */
    @Override
    public void saveArticleToWord(String filePathOut) {
        // 1. 获取数据。
        List<Books> list = booksService.list();
        for (Books books : list) {
            String name = books.getName();
            String question = books.getQuestion();
            String questionEn = books.getQuestionEn();
            String series = books.getSeries();
            outWord(name, question, series, NumberConstant.ONE, filePathOut);
            outWord(name, questionEn, series, NumberConstant.ZERO, filePathOut); //中文

        }
    }

    public void outWord(String name, String word, String series, int wordType, String filePathOut) {
        String filePathAdd = "";
        if (wordType == NumberConstant.ZERO) {
            filePathAdd = "(中文版)";
        } else {
            filePathAdd = "(英文版)";
        }
        name = sanitizeFileName(name);
        try {
            // Apache POI XWPF对象
            // 创建一个新的Word文档
            XWPFDocument document = new XWPFDocument();

            // 根据换行符分割问题文本
            String[] lines = word.split("\r\n|\r|\n"); // 匹配不同类型的换行符

            // 添加第一个字段的内容
            for (String line : lines) {
                // 为每行创建一个新的段落
                XWPFParagraph paragraph = document.createParagraph();
                XWPFRun run = paragraph.createRun();
                run.setText(line);
            }

            // 可选：在两个字段之间添加一个分隔符或空行
            String baseDir = filePathOut + series + "\\" + name;
            String fileName = name + filePathAdd + ".docx";
            Path dirPath = Paths.get(baseDir);

            // 检查并创建目录
            if (!Files.exists(dirPath)) {
                Files.createDirectories(dirPath);
                System.out.println("目录已创建：" + dirPath.toString());
            }

            // 定义完整的文件路径
            Path filePath = dirPath.resolve(fileName);

            // 写入文件
            try (FileOutputStream out = new FileOutputStream(filePath.toFile())) {
                document.write(out);
                System.out.println("文档已成功保存为：" + filePath.toString());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }


    // 函数用于清理文件名中的非法字符
    private static String sanitizeFileName(String name) {
        return name.replaceAll("[^\\u4e00-\\u9fa5a-zA-Z0-9.-]", "_");
    }


}
